package main

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/websocket"
	_ "github.com/mattn/go-sqlite3"
	"github.com/mitchellh/mapstructure"
	"log"
	"real-time-communication/utils"
	"strconv"
)

type Client struct {
	Ip   string
	Port string
	User *User
	Conn *websocket.Conn
}

type WebSocketMsg struct {
	SendType string      `json:"sendType"`
	Data     interface{} `json:"data"`
}

const (
	ALIVE = "ALIVE"

	// 发送消息
	sendMsg        = "SendMsg"
	sendMsgSuccess = "sendMsgSuccess"
	receiveMsg     = "receiveMsg"

	// 好友业务
	applyFriend        = "applyFriend"
	receiveApplyFriend = "receiveApplyFriend"
	respFriend         = "respFriend"
	receiveRespFriend  = "receiveRespFriend"

	// 端对端通话
	applyP2PCall                   = "applyP2PCall"
	receiveApplyP2PCall            = "receiveApplyP2PCall"
	respP2PCall                    = "respP2PCall"
	receiveRespP2PCall             = "receiveRespP2PCall"
	notifyP2PFrameBuilt            = "notifyP2PFrameBuilt"
	receiveP2PFrameBuilt           = "receiveP2PFrameBuilt"
	sendP2PCallIce                 = "sendP2PCallIce"
	receiveP2PCallIce              = "receiveP2PCallIce"
	sendP2PCallOffer               = "sendP2PCallOffer"
	receiveP2PCallOffer            = "receiveP2PCallOffer"
	sendP2PCallAnswer              = "sendP2PCallAnswer"
	receiveP2PCallAnswer           = "receiveP2PCallAnswer"
	callP2PRemoteDisconnect        = "callP2PRemoteDisconnect"
	receiveP2PCallRemoteDisconnect = "receiveP2PCallRemoteDisconnect"

	// 退出登录
	logout = "logout"
)

func NewClient(ip, port string, user *User, conn *websocket.Conn) *Client {
	client := &Client{
		Ip:   ip,
		Port: port,
		User: user,
		Conn: conn,
	}
	return client
}

func (c *Client) ListenNewMessage() {

	defer func() {
		c.Conn.Close()
	}()

	for {
		_, msg, err := c.Conn.ReadMessage()
		if err != nil {
			log.Println("Error reading message from client:", err)
			c.LogoutClient()
			break
		}

		var webSocketMsg WebSocketMsg
		err = json.Unmarshal(msg, &webSocketMsg)
		if err != nil {
			log.Fatal("JSON解码失败")
			return
		}

		fmt.Println("接收到前端请求：", webSocketMsg)

		switch webSocketMsg.SendType {
		case ALIVE:
			{
				err = c.Conn.WriteMessage(websocket.TextMessage, []byte("pong"))
				if err != nil {
					log.Println("Error sending heartbeat response:", err)
					break
				}
				break
			}
		case sendMsg:
			{
				var message Message
				err := mapstructure.Decode(webSocketMsg.Data, &message)
				if err != nil {
					log.Println("类型转换失败:", err)
					break
				}

				if message.Sender == c.User.UserId {
					AddMessage(message)
					chatMessage := QueryLastTimeMessage(message.Sender, message.Receiver)
					redisKey := "LastRead:" + strconv.Itoa(c.User.UserId) + ":" + chatMessage.MsgId
					err = Rdb.Set(Ctx, redisKey, chatMessage.Id, 0).Err() // 永远不过期
					var socketMsg WebSocketMsg
					socketMsg.SendType = sendMsgSuccess
					res, err := json.Marshal(socketMsg)
					if err != nil {
						log.Fatal("Json编码失败:", err)
					}

					err = c.Conn.WriteMessage(websocket.TextMessage, res)
					if err != nil {
						log.Fatal("转发错误:", err)
					}
				}

				if !utils.IsObjNil(&message) {
					if _, ok := clients[message.Receiver]; ok {
						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveMsg
						socketMsg.Data = message
						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[message.Receiver].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					}
				}
				break
			}
		case applyFriend:
			{
				var friend Friend
				err := mapstructure.Decode(webSocketMsg.Data, &friend)
				if err != nil {
					log.Println("类型转换失败:", err)
					break
				}

				if friend.Applier == c.User.UserId {
					ApplyFriend(friend.Applier, friend.Receiver) // 新增关系
				}

				// 如果被申请人是该用户的话，则转发该消息
				if !utils.IsObjNil(&friend) {
					if _, ok := clients[friend.Receiver]; ok {
						redisKey := "FriendApply:" + strconv.Itoa(friend.Receiver)
						err = Rdb.Set(Ctx, redisKey, 1, 0).Err() // 永远不过期

						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveApplyFriend
						socketMsg.Data = friend

						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[friend.Receiver].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					}
				}
				break
			}
		case respFriend:
			{
				var friend Friend
				err := mapstructure.Decode(webSocketMsg.Data, &friend)
				if err != nil {
					log.Println("类型转换失败:", err)
					break
				}

				if friend.Receiver == c.User.UserId {
					UpdateFriendStatus(friend.Applier, friend.Receiver, friend.Status)
				}

				// 通知发起人，更新好友列表
				if !utils.IsObjNil(&friend) {
					if _, ok := clients[friend.Applier]; ok {
						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveRespFriend
						socketMsg.Data = friend

						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[friend.Applier].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					}
				}
				break
			}
		case applyP2PCall:
			{
				var p2pCall ApplyP2PCall
				err := mapstructure.Decode(webSocketMsg.Data, &p2pCall)
				if err != nil {
					log.Println("类型转换失败:", err)
					break
				}

				if !utils.IsObjNil(&p2pCall) {
					if _, ok := clients[p2pCall.TargetId]; ok {
						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveApplyP2PCall
						socketMsg.Data = p2pCall

						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[p2pCall.TargetId].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					} else {
						resp := &ResponseP2PCall{
							UserId:     p2pCall.TargetId,
							TargetId:   p2pCall.UserId,
							RespStatus: false,
							Reason:     "对方不在线",
						}
						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveRespP2PCall
						socketMsg.Data = resp

						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[p2pCall.UserId].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					}
				}
				break
			}
		case respP2PCall:
			{
				var resp ResponseP2PCall
				err := mapstructure.Decode(webSocketMsg.Data, &resp)
				if err != nil {
					log.Println("类型转换失败:", err)
					break
				}

				if !utils.IsObjNil(&resp) {
					if _, ok := clients[resp.TargetId]; ok {
						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveRespP2PCall
						socketMsg.Data = resp

						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[resp.TargetId].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					}
				}
				break
			}
		case notifyP2PFrameBuilt:
			{
				// 通知对方，窗口已打开，可以传输信息
				var notice NotifyFrameBuilt
				err := mapstructure.Decode(webSocketMsg.Data, &notice)
				if err != nil {
					log.Println("类型转换失败:", err)
					break
				}

				if !utils.IsObjNil(&notice) {
					if _, ok := clients[notice.TargetId]; ok {
						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveP2PFrameBuilt
						socketMsg.Data = notice

						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[notice.TargetId].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					}
				}
				break
			}
		case sendP2PCallIce:
			{
				var iceData IceP2PCall
				err := mapstructure.Decode(webSocketMsg.Data, &iceData)
				if err != nil {
					log.Println("类型转换失败:", err)
					break
				}

				if !utils.IsObjNil(&iceData) {
					if _, ok := clients[iceData.TargetId]; ok {
						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveP2PCallIce
						socketMsg.Data = iceData

						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[iceData.TargetId].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					}
				}
				break
			}
		case sendP2PCallOffer:
			{
				var descData DescriptionP2PCall
				err := mapstructure.Decode(webSocketMsg.Data, &descData)
				if err != nil {
					log.Println("类型转换失败:", err)
					break
				}

				if !utils.IsObjNil(&descData) {
					if _, ok := clients[descData.TargetId]; ok {
						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveP2PCallOffer
						socketMsg.Data = descData

						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[descData.TargetId].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					}
				}
				break
			}
		case sendP2PCallAnswer:
			{
				var descData DescriptionP2PCall
				err := mapstructure.Decode(webSocketMsg.Data, &descData)
				if err != nil {
					log.Println("类型转换失败:", err)
					break
				}

				if !utils.IsObjNil(&descData) {
					if _, ok := clients[descData.TargetId]; ok {
						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveP2PCallAnswer
						socketMsg.Data = descData

						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[descData.TargetId].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					}
				}
				break
			}
		case callP2PRemoteDisconnect:
			{
				// 通知对方断开连接
				var notice NotifyFrameBuilt
				err := mapstructure.Decode(webSocketMsg.Data, &notice)
				if err != nil {
					log.Println("类型转换失败:", err)
					break
				}

				if !utils.IsObjNil(&notice) {
					if _, ok := clients[notice.TargetId]; ok {
						var socketMsg WebSocketMsg
						socketMsg.SendType = receiveP2PCallRemoteDisconnect
						socketMsg.Data = notice

						res, err := json.Marshal(socketMsg)
						if err != nil {
							log.Fatal("Json编码失败:", err)
						}

						err = clients[notice.TargetId].Conn.WriteMessage(websocket.TextMessage, res)
						if err != nil {
							log.Fatal("转发错误:", err)
						}
					}
				}
				break
			}
		case logout:
			{
				c.LogoutClient()
				break
			}
		}
	}
}

func (c *Client) LogoutClient() {
	log.Println("客户端下线...")
	delete(clients, c.User.UserId)
	err := c.Conn.Close()
	if err != nil {
		return
	}
}
